monoruby: invariants
class version
クラス・メソッドが定義(・再定義・削除・エイリアス)されるごとにインクリメントされるカウンタ
同一のclass versionであれば同じレシーバとメソッド名の組は同じメソッドに解決されることが保証される。
一つのcompilation unit内のメソッド解決は同じclass versionが前提となっているため、更新されるとすべてのメソッド解決が無効となる。
class versionが更新されたことを察知したらunit内のすべてのメソッド解決をやりなおし、一つでも違うメソッドに変わるものがあればrecompileする。すべて同じならunit全体のclass versionを更新してJITコードの実行を続行
実行パス上にクラス定義・メソッド定義がある場合にはコンパイル中止
basic operations
Integer#+などの基本的なメソッドが再定義されるとJITコードはもちろん、インタプリタのバイトコード処理コードも無効になる。
現在の実装ではbasic operationsの再定義を検知したら、直ちに全てのJITコードを無効化し、インタプリタのジャンプテーブルを書き換えて最適化のない処理コードを走らせるようにしている。
frame capture
ローカル変数がキャプチャされると、クロージャオブジェクトを通じて静的にわからない形でローカル変数にアクセスされる可能性があり、JITコードの実行継続が不可能となる。
キャプチャの瞬間にはローカル変数フレーム内にオブジェクトを正しく配置されていることが保証される必要がある。
code:Ruby
def f
eval("a = 42", $b)
end
$b = binding
a = 100
f
puts a # => 42
フレームをキャプチャする(し得る)メソッド(eval & binding)に遭遇したらコンパイル中止
上記以外のブロックをとらないメソッド呼び出しに関してはチェック不要。
ブロックを取るspecializeされたメソッドに関しては、ブロック内で上記のチェックを行う。
ブロックを取りspecializeできないメソッドは「信用できないメソッド」として扱う。
「信用できないメソッド」を実行した後に必ずinvariantsをチェックし、failしていたらdeoptimize